/*
 * Copyright 2015-2018 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.willowtreeapps.opentest4k

import kotlin.test.*

/**
 * Unit tests for [AssertionFailedError].
 *
 * @author Marc Philipp
 * @author Sam Brannen
 * @since 1.0
 */
class AssertionFailedErrorTests {

    @Test
    fun defaultConstructorUsesEmptyMessage() {
        assertEquals(EMPTY, AssertionFailedError().message)
    }

    @Test
    fun nullMessageIsConvertedToEmptyMessage() {
        assertEquals(EMPTY, AssertionFailedError(null).message)
        assertEquals(EMPTY, AssertionFailedError(null, null).message)
        assertEquals(EMPTY, AssertionFailedError(null, "foo", "bar").message)
        assertEquals(EMPTY, AssertionFailedError(null, "foo", "bar", null).message)
    }

    @Test
    fun blankMessageIsConvertedToEmptyMessage() {
        assertEquals(EMPTY, AssertionFailedError(BLANK).message)
        assertEquals(EMPTY, AssertionFailedError(BLANK, null).message)
        assertEquals(EMPTY, AssertionFailedError(BLANK, "foo", "bar").message)
        assertEquals(EMPTY, AssertionFailedError(BLANK, "foo", "bar", null).message)
    }

    @Test
    fun toStringChecks() {
        val className = AssertionFailedErrorName
        assertEquals(className, AssertionFailedError().toString())
        assertEquals(className, AssertionFailedError(null).toString())
        assertEquals("$className: message", AssertionFailedError("message").toString())

        assertEquals(className, AssertionFailedError(null, "foo", "bar").toString())
        assertEquals(className, AssertionFailedError(null, RuntimeException()).toString())
        assertEquals(className, AssertionFailedError(null, "foo", "bar", RuntimeException()).toString())

        assertEquals(className, AssertionFailedError(EMPTY).toString())
        assertEquals(className, AssertionFailedError(EMPTY, "foo", "bar").toString())
        assertEquals(className, AssertionFailedError(EMPTY, RuntimeException()).toString())
        assertEquals(className, AssertionFailedError(EMPTY, "foo", "bar", RuntimeException()).toString())

        assertEquals(className, AssertionFailedError(BLANK).toString())
        assertEquals(className, AssertionFailedError(BLANK, "foo", "bar").toString())
        assertEquals(className, AssertionFailedError(BLANK, RuntimeException()).toString())
        assertEquals(className, AssertionFailedError(BLANK, "foo", "bar", RuntimeException()).toString())

        assertEquals("$className: message", AssertionFailedError("message").toString())
        assertEquals("$className: message", AssertionFailedError("message", "foo", "bar").toString())
        assertEquals("$className: message", AssertionFailedError("message", RuntimeException()).toString())
        assertEquals(
            "$className: message",
            AssertionFailedError("message", "foo", "bar", RuntimeException()).toString()
        )
    }

    @Test
    fun messageAndCauseAreStored() {
        val cause = RuntimeException("cause")

        val error = AssertionFailedError("my message", cause)

        assertEquals("my message", error.message)
        assertEquals(cause, error.cause)
        assertFalse(error.isExpectedDefined)
        assertFalse(error.isActualDefined)
    }

    @Test
    fun expectedAndActualValuesAreStored() {
        val errorWithExpectedAndActual = AssertionFailedError(null, "foo", "bar")
        assertTrue(errorWithExpectedAndActual.isExpectedDefined)
        assertEquals("foo", errorWithExpectedAndActual.expected?.value)
        assertTrue(errorWithExpectedAndActual.isActualDefined)
        assertEquals("bar", errorWithExpectedAndActual.actual?.value)
    }

    @Test
    fun returnsNullForExpectedAndActualWhenNotPassedToConstructor() {
        val errorWithoutExpectedAndActual = AssertionFailedError()
        assertFalse(errorWithoutExpectedAndActual.isExpectedDefined)
        assertNull(errorWithoutExpectedAndActual.expected)
        assertFalse(errorWithoutExpectedAndActual.isActualDefined)
        assertNull(errorWithoutExpectedAndActual.actual)
    }
}

const val EMPTY = ""
const val BLANK = "   "